package org.embedchat.protocol.codec;

import org.apache.mina.common.ByteBuffer;
import org.apache.mina.common.IoSession;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.mina.filter.codec.demux.MessageDecoder;
import org.apache.mina.filter.codec.demux.MessageDecoderResult;

import org.embedchat.protocol.Constants;
import org.embedchat.protocol.message.AbstractMessage;

public abstract class AbstractMessageDecoder implements MessageDecoder {

	private final int type;
	private boolean readHeader;

	protected AbstractMessageDecoder(int type) {
		this.type = type;
	}

	public MessageDecoderResult decodable(IoSession session, ByteBuffer in) {
		// Return NEED_DATA if the whole header is not read yet.
		if (in.remaining() < Constants.HEADER_LEN) {
			return MessageDecoderResult.NEED_DATA;
		}
		// Return OK if type and bodyLength matches.
		int connamdId = in.getShort();
		// Read body length
		in.getLong();
		if (type == connamdId) {
			return MessageDecoderResult.OK;
		}
		return MessageDecoderResult.NOT_OK;
	}

	public MessageDecoderResult decode(IoSession session, ByteBuffer in,
			ProtocolDecoderOutput out) throws Exception {
		// Try to skip header if not read.
		long bodyLengthInt = 0;
		if (!readHeader) {
			in.getShort();
			bodyLengthInt = in.getLong();
			readHeader = true;
		}
		AbstractMessage m = decodeBody(session, in, bodyLengthInt);
		if (m == null) {
			return MessageDecoderResult.NEED_DATA;
		} else {
			readHeader = false;
		}
		out.write(m);
		return MessageDecoderResult.OK;
	}

	protected abstract AbstractMessage decodeBody(IoSession session,
			ByteBuffer in, long bodyLengthString);
}
